Bug 6648001

Bug Description:

This is a wait-notify deadlock bug.
Deadlock thread trace:

"ServerRunner-1" prio=6 tid=0x0000000005f9e000 nid=0x1d68 in Object.wait() [0x0000000006bef000..0x0000000006bef910]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x0000000040006448> (a java.util.HashMap)
	at java.lang.Object.wait(Object.java:485)
	at sun.net.www.protocol.http.AuthenticationInfo.requestIsInProgress(AuthenticationInfo.java:117)
	- locked <0x0000000040006448> (a java.util.HashMap)
	at sun.net.www.protocol.http.AuthenticationInfo.getServerAuth(AuthenticationInfo.java:258)
	at sun.net.www.protocol.http.HttpURLConnection.getServerAuthentication(HttpURLConnection.java:1632)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1091)
	- locked <0x0000000040147e68> (a sun.net.www.protocol.http.HttpURLConnection)
	at Test6648001$Runner.run(Test6648001.java:119)
    
More details about this bug are at JDK-6648001 JIRA page.

Interleaving Description:

        
sun.net.www.protocol.http.HttpURLConnection
        
t1  t2  public synchronized InputStream getInputStream() throws IOException { 
            ...
1   5       serverAuthentication = getServerAuthentication(srvHdr);
            ...
            finally {
                if (respCode == HTTP_PROXY_AUTH && proxyAuthentication != null) {
                    proxyAuthentication.endAuthRequest();
                } 
8               else if (respCode == HTTP_UNAUTHORIZED && serverAuthentication != null) {
9                   serverAuthentication.endAuthRequest();
                }
            }
        }
        
sun.net.www.protocol.http.AuthenticationInfo
        
        static private boolean requestIsInProgress (String key) {
            if (!serializeAuth) {
                /* behavior is disabled. Revert to concurrent requests */
                return false;
            }
            synchronized (requests) {
                Thread t, c;
                c = Thread.currentThread();
2   6           if ((t=(Thread)requests.get(key))==null) {
3                   requests.put (key, c);
4                   return false;
                }
                if (t == c) {
                    return false;
                }
                while (requests.containsKey(key)) {
                    try {
    7                   requests.wait ();
                    } catch (InterruptedException e) {}
                }
            }
            /* entry may be in cache now. */
            return true;
        }
	

a) thread 1 tries to get serverAuthentication at 1 and it goes to 2 to get the value of key from requests. But the key's value has not set before, so it's null here.
b) thread 1 put the value of key into requests at 3, and return false at 4.
c) serverAuthentication is set to null finally at 1.
d) context switched, thread 2 comes to 5 and checks the value of the same key at 6. This time it's not null because of the put action at step b). And it comes to 7 to wait.
e) context switched, now thread 1 comes to 8. thread 2 could be notified to continue if 9 is executed. But at 8, as serverAuthentication is null due to step a), 9 will not be reached. So thread 2 will wait forever.

How To Reproduce:

This bug is reproduced under JDK 1.6.0.
It started at JDK 1.6.0, and has been fixed since JDK 1.6.0_10.
Execute the following scripts to run the test to reproduce the bug (assume the location of the jdk6 test project is jdk_test_home).

Linux:
${jdk_test_home}/scripts/6648001.sh [--monitoroff] [--javaloc path]
Windows:
%jdk_test_home%\scripts\6648001.bat [--monitoroff] [--javaloc path]

Example:
Use monitor to report and terminate the program when deadlock happens:
${jdk_test_home}/scripts/6648001.sh


Turn off monitor:
${jdk_test_home}/scripts/6648001.sh --monitoroff

Option Function
--monitoroff, -mo Turn off to stop reporting bug messages and ending program when test
runs into the expected concurrency bug which is a deadlock.
User has to terminate the program manually when this option is set.
--javaloc The location of JDK that is eligible to reproduce the bug, if your java environment is not eligible.
In this case, it's JDK 1.6.0. It should be the absolute path to the JDK's java starter and ended with "/".
For example: ~/jdk/home/jdk1.6.0/bin/